package com.myjob.controller;

import com.alibaba.fastjson.JSONObject;
import com.myjob.dto.AuthTreeDto;
import com.myjob.entity.*;
import com.myjob.enums.RedisEnums;
import com.myjob.exception.OptionException;
import com.myjob.response.Result;
import com.myjob.service.*;
import com.myjob.utils.RedisUtil;
import com.myjob.utils.UtilValidate;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.web.bind.annotation.*;

import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @author Chen Yuan
 * @create 2021-03-22  9:13
 */
@Slf4j
@RestController
@RequestMapping("/account/auth")
public class AuthController {
	@Autowired
	private AuthService authService;
	@Autowired
	private RedisUtil redisUtil;
	@Autowired
	private ResourceService resourceService;
	@Autowired
	private RoleResourceRelService roleResourceRelService;

	@GetMapping("/tree")
	public Result getAuthTree(){
		Result result = null;
		try {
			List<AuthTreeDto> authTree = authService.getAuthTree();

			if (UtilValidate.isNotEmpty(authTree)) {
				result = Result.succeed(authTree, "权限树获取成功");
			}else {
				result = Result.failed("权限树为空");
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new OptionException("获取权限树异常");
		}
		return result;
	}

	@GetMapping("/checked")
	public Result getAllChecked(@RequestParam("roleId") String roleId){
		Result result = null;
		try {
			List<String> allChecked = authService.getAllChecked(roleId);
			result = Result.succeed(allChecked, "成功获取拥有权限");
		} catch (Exception e) {
			e.printStackTrace();
			throw new OptionException("获取拥有权限异常");
		}
		return result;
	}

	@GetMapping("/getRoleList")
	public Result getRoleList(){
		Result result = null;
		try {
			List<Role> roleList = authService.getRoleList();
			if (UtilValidate.isNotEmpty(roleList)) {
				result = Result.succeed(roleList);
			}else {
				result = Result.failed("列表为空");
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new OptionException("获取角色列表失败");
		}
		return result;
	}

	@PostMapping("/updateAuth")
	public Result updateAuth(@RequestParam("roleId") String roleId,
	                         @RequestParam("roleList") String roleList){
		Result result = null;
		try {
			List<String> list = JSONObject.parseObject(roleList, List.class);
			Boolean update = authService.updateAuth(roleId, list);
			if (update) {
				log.info("成功更新权限信息，刷新 Redis 信息");
				this.updateAllRoleResourceRel();
				result = Result.succeed("更新成功");
			}else {
				result = Result.failed("更新权限失败");
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new OptionException("更新权限异常");
		}
		return result;
	}


	public void updateAllRoleResourceRel(){
		// 查询出所有的资源信息
		List<RoleResourceRel> roleResources = roleResourceRelService.list();
		List<Resource> resources = resourceService.list();

		HashMap<String, Resource> resourceMap = new HashMap<>();
		for (Resource resource : resources) {
			resourceMap.put(String.valueOf(resource.getResourceId()), resource);
		}

		// 将 resourceUrl 和 roleId 对应关系存进 Redis
		this.setUrlAndRoleIdsRelToRedis(roleResources, resourceMap);
		// 将 roleId 和 resourceCode 对应关系存进 Redis
		this.setRoleIdAndResourceCodeToRedis(roleResources, resourceMap);
	}

	@Async
	public Boolean setUrlAndRoleIdsRelToRedis(List<RoleResourceRel> roleResources,
	                                          HashMap<String, Resource> resourceMap){
		HashMap<String, List<String>> roleResourceMap = new HashMap<>();
		for (RoleResourceRel roleResource : roleResources) {
			String resourceId = String.valueOf(roleResource.getResourceId());
			Resource resource = resourceMap.get(resourceId);
			String key = resource.getResourceMethod() + "-" + resource.getResourceUrl();
			List<String> list = roleResourceMap.get(key);
			if (UtilValidate.isEmpty(list)){
				list = new ArrayList<>();
			}
			list.add("["+roleResource.getRoleId()+"]");
			roleResourceMap.put(key, list);
		}
		log.info("<< AUTH >> --- 正在将 (资源URL, 角色ID) 关系信息存入 Redis");
		boolean hmset = redisUtil.hmset(RedisEnums.KEY_IN_REDIS.AUTH_RESOURCE_URL_ROLE_IDS_CEL.getValue(), roleResourceMap, 12, TimeUnit.HOURS);
		if (!hmset){
			// 不成功重试一次
			log.info("<< AUTH >> --- 出错, 进行重试");
			hmset = redisUtil.hmset(RedisEnums.KEY_IN_REDIS.AUTH_RESOURCE_URL_ROLE_IDS_CEL.getValue(), roleResourceMap, 12, TimeUnit.HOURS);
		}
		log.info("<< AUTH >> --- 成功将 (资源URL, 角色ID) 关系信息存入 Redis");
		return hmset;
	}

	@Async
	public Boolean setRoleIdAndResourceCodeToRedis(List<RoleResourceRel> roleResources,
	                                               HashMap<String, Resource> resourceMap){
		HashMap<String, List<String>> roleResourceMap = new HashMap<>();
		for (RoleResourceRel roleResource : roleResources) {
			String key = String.valueOf(roleResource.getRoleId());
			String resourceId = String.valueOf(roleResource.getResourceId());
			Resource resource = resourceMap.get(resourceId);
			List<String> resources = roleResourceMap.get(key);

			if (UtilValidate.isEmpty(resources)) {
				resources = new ArrayList<>();
			}

			resources.add(resource.getResourceCode());
			roleResourceMap.put(key, resources);
		}
		log.info("<< AUTH >> --- 正在将 (角色ID, 资源Code) 关系信息存入 Redis");
		boolean hmset = redisUtil.hmset(RedisEnums.KEY_IN_REDIS.AUTH_ROLE_ID_RESOURCE_CODE_CEL.getValue(), roleResourceMap, 12, TimeUnit.HOURS);
		if (!hmset){
			// 不成功重试一次
			log.info("<< AUTH >> --- 出错, 进行重试");
			hmset = redisUtil.hmset(RedisEnums.KEY_IN_REDIS.AUTH_ROLE_ID_RESOURCE_CODE_CEL.getValue(), roleResourceMap, 12, TimeUnit.HOURS);
		}
		log.info("<< AUTH >> --- 成功将 (角色ID, 资源Code) 关系信息存入 Redis");
		return hmset;
	}

}
